package reflectx

import (
	"errors"
	"gitee.com/zhongguo168a/gocodes/datax/schemax"
	"gitee.com/zhongguo168a/gocodes/datax/schemax/basickind"
	"sync"
)

var (
	data = &sync.Map{}
)

func AddTypeList(reftypes []IRefType) {
	for _, val := range reftypes {
		data.Store(val.RefType(), val)
	}

}

func AddType(reftype IRefType) {
	data.Store(reftype.RefType(), reftype)
}

func GetTypeByKey(key string) IRefType {
	val, has := data.Load(key)
	if !has {
		return nil
	}
	return val.(IRefType)
}

func GetType(key string) IRefType {
	return GetTypeByKey(key)
}

func NewObject(key string) (val IRefObject, err error) {
	stdesc := schemax.GetDeclByKey(key)
	if stdesc == nil {
		err = errors.New("schema not found: " + key)
		return
	}

	ref := GetType(key)
	if ref == nil {
		err = errors.New("reftype not found: " + key)
		return
	}
	obj := ref.RefNew()
	initObj(obj, stdesc.(*schemax.ClassDecl))
	return obj, nil
}

func initObj(obj IRefObject, desc *schemax.ClassDecl) (err error) {
	for _, field := range desc.Fields {
		fname := field.Name
		switch ftyp := field.Type.(type) {
		case *schemax.ClassType:
			if field.Value == "{}" {
				st, newerr := NewObject(ftyp.Decl)
				if newerr != nil {
					err = errors.New("new object: " + err.Error())
					return
				}
				obj.(IRefField).RefSet(obj, fname, st)
			}
		case *schemax.ArrayType:
		case *schemax.MapType:
			if field.Value == "{}" {
				obj.(IRefMap).RefMapNew(fname)
			}
		case *schemax.EnumType:
			if field.Value == "" {
				continue
			}
			idesc := schemax.GetDeclByKey(ftyp.Decl)
			if idesc == nil {
				err = errors.New("description not found: " + ftyp.Decl)
				return
			}

			enumdesc := idesc.(*schemax.EnumDecl)
			obj.(IRefField).RefSet(obj, field.Name, enumdesc.ConvertToValue(field.Value))
		case *schemax.BasicType:
			if field.Value == "" {
				continue
			}
			obj.(IRefField).RefSet(obj, field.Name, basickind.ConvertKindToStruct(ftyp.Kind, field.Value))
		case *schemax.AnyType:
		}
	}
	return
}
